package com.tyylab.kestrel.framework.spring.rpc.feign.impl;

import cn.hutool.core.util.StrUtil;
import com.tyylab.kestrel.framework.core.annoutil.SpringCoreAnnotationUtil;
import com.tyylab.kestrel.framework.core.build.DefaultClassBuilder;
import com.tyylab.kestrel.framework.core.build.IClassBuilder;
import lombok.SneakyThrows;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;
import java.lang.reflect.Type;

import static com.tyylab.kestrel.framework.spring.rpc.feign.util.ConstValue.KestrelImplSubFix;

/**
 * 生成接口类的实现类，使用Feign实现远程调用。
 */
public class ImplWithFeignGenerator {
    @SneakyThrows
    public Class generate(Class<?> api, Class<?> feignApi) {
        String className = api.getName() + KestrelImplSubFix;
        //
        IClassBuilder classBuilder = new DefaultClassBuilder();
        String instanceName = StrUtil.lowerFirst(api.getSimpleName() + KestrelImplSubFix);

        classBuilder  =
        classBuilder.defineClass().clazz(className,null, api,IFeignSupport.class)
                .modifiers(Modifier.PUBLIC)
                .annotate(SpringCoreAnnotationUtil.service(instanceName))
                .end();

        //add feign api as autowired property
        classBuilder  =
        classBuilder.defineProperty()
                .property("feign", feignApi, false)
                .annotate(SpringCoreAnnotationUtil.autowired(true))
                .end();

        Method[] methods = api.getDeclaredMethods();
        for (Method method : methods) {
            String methodName = method.getName();
//            String methodParamsEntityName = ProxyMethodNameStrategy.generateMethodParamsEntityClassName(method);
            //add method
            IClassBuilder.IMethodDefine md =
                classBuilder.defineMethod()
                        .method(methodName, method.getGenericReturnType(), Modifier.PUBLIC);
            IClassBuilder.IParamDefine pd = null;
            Parameter[] params = method.getParameters();
            Type[] paramTypes = method.getGenericParameterTypes();
            int i = 0;
            if (null!=params && params.length>0) {
                for (Parameter param : params) {
                    if (null == pd) {
                        pd = md.param(params[i].getName(), paramTypes[i], params[i].getModifiers());
                    }
                    else{
                        pd = pd.param(params[i].getName(), paramTypes[i], params[i].getModifiers());
                    }
                    i ++;
                }
            }
            if (null != pd) {
                md = pd.end();
            }
            // impl
            md.impl().delegate(FeignInvokeInterceptor.class);
            //end
            classBuilder = md.end();
        }

        return classBuilder.build();
    }
}
